

                            THE DUNGEON MASTER

                       AN ALTERNATIVE MODULE SYSTEM



                                Sue Felshin
           Laboratory for Advanced Technology in the Humanities

       Copyright (c) 1993 Massachusetts Institute of Technology
   Permission is granted to distribute this document, provided that this
copyright notice is retained intact.  This document is covered by the Free
 Software Foundation GNU General Public License, Version 1, February 1989.



   The Dungeon Master (or DM) is a set of routines that simplifies the
loading and compilation of large programs.  The DM works in terms of
modules, which correspond roughly to files.  For each module, the DM
records when it was last loaded, what other modules it depends on, and
other information.  The DM assures that modules are loaded and compiled
when necessary and in the correct order.  In a large system, file
dependencies are complex and frequently circular.  Modules can request that
other modules be loaded, but, in order to prevent infinite loops, the DM
will not in general load any module already in the process of being
loaded.(There are exceptions to this rule that vary from implementation to
implementation of Common Lisp.  The DM is parameterized to know about the
exceptions in various dialects of Common Lisp.)
   The DM is an extension of the module system described in Section 11.8 of
Common Lisp: the Language, but is incompatible with that system to the
extent that it requires a one-to-one correspondence between modules and
files.
   This document describes how to use the DM within modules and
interactively.



1. Initialization Routines


push-module-search-path name                                     [Function]

   The directory name is added to the front of the module search path.  Do
not forget to add a trailing directory separator to name if your operating
system requires it to construct the pathname.


                              Copyright (C)
2. Module to Module Interface

   Use these routines in modules; that is, in source code.  Functions in
the next section are handier for using the Dungeon Master interactively.


provide-module name &key (compile t) (documentation nil)            [Macro]

   Name may be a string or a symbol.  If a symbol, the name of the module
will be the print name of the symbol.  Symbols are generally more
convenient to use than strings, and in order to prevent package conflicts,
it is a convention to give all module names as keywords.
   If compile is nil, the module will never be compiled by any DM function.
This may be appropriate for some data files.  Documentation specifies a
documentation string to be associated with the module.
   A provide-module statement should appear at the top of each module,
immediately below the call to in-package.  This statement declares the name
of the module.  It is an error for a file to contain more than one
provide-module statement.  If a file is treated as a module, but contains
no call to provide-module, a continuable error is signalled.
   When a module finishes loading, it is marked as successfully loaded and
the DM remembers such information as what file the module was loaded from,
the time at which it was loaded, and whether or not a compiled version was
loaded.  The DM also remembers all of the modules dependencies, based on
the calls to require-module contained directly within the module; this list
is reset when a module is reloaded, so that it is always accurate.


require-module module &key path (eval :load) (load :load)           [Macro]
                           (compile :load) (when t)
                           (macros nil) (inlines nil)
                           (accessors nil) (modifiers nil)
                           (constructors nil) (includes nil)
                           (classes nil) (specializers nil)
                           (read-macros nil)
                           (toplevel-calls nil)

   Require-module ensures that definitions in another module are available
to the current module.  Typically this involves loading (and possibly
compiling) the other module, but this is not always necessary.  The DM
determines what action needs to be taken based on the keyword arguments to
require-module.


     path      Require-module finds a file to load by checking the
               search path for a file with the same name as the module
               (adjusted to fit the file naming standards of the
               operating system).  Use this keyword to override the
               module name, bypass the search path, or otherwise
               change what path is used to find the module's file.
     eval, load, and compile
               It is possible, though not common, for a required
               module not to be required under certain circumstances.
               For instance, a file containing only data may be
               required to run code in a module, but not to compile
               it.(Note that if the "data" file exports symbols or
               proclaims the types of variables, then it is not a
               "pure" data file and is required for compilation.)  A
               file containing reader macros may be required to eval
               or compile a file, but not to load it.  If the required
               module is not required under one of these
               circumstances, set the corresponding argument to nil.
     when      If this argument is provided and evaluates to nil, then
               the require-module form will be ignored.  In a large
               system with many subsystems, one module might only
               require another module when a certain subsystem is
               being loaded.
     macros    If the current module calls any macros in the required
               module, then this argument should be t.
     inlines   If the current module calls any functions in the
               required module which have been proclaimed or declared
               inline, then this argument should be t.(If you are
               running Lucid Common Lisp 01.01.0000 on the IBM RT
               running AIX Release 1.2 Version 2, be warned that due
               to a bug, it is necessary to set this argument to t if
               the function is proclaimed inline, even if it is
               locally declared notinline.)
     accessors If the current module calls any structure accessor
               functions defined in the required module, this argument
               should be t.
     modifiers If the current module performs any setfs on structure
               accessors defined in the required module, this argument
               should be t.
     constructors
               If the current module calls any structure constructor
               functions defined in the required module, this argument
               should be t.
     includes  If the current module includes any structures defined
               in the required module, this argument should be t.
     classes   If the current module defines classes based on classes
               defined in the required module, this argument should be
               t.
     specializers
               If the current module defines methods whose
               specializers include types (classes or other types)
               defined in the required module, this argument should be
               t.
     read-macros
               If the current module uses any reader macros defined in
               the required module, this argument should be t.
     toplevel-calls
               If the current module makes toplevel calls to
               functions, macros, or variables defined in the required
               module, this argument should be t.


   If the DM decides that the required module needs to be loaded, it calls
find-module-file with module and path to determine the file to load.


mload-protect &body body                                            [Macro]

   Executes body when the current module is done loading or compiling, even
if there is an abnormal exit before loading or compilation is complete.
This is typically used to ensure that temporary reader macros are removed
from the Lisp environment.



3. Interactive Interface

   These routines may be used from the Lisp Listener.  It is tasteless to
use them in source code.


unprovide-module module                                          [Function]

   Module may be a string or symbol, as for provide-module.  The DM deletes
all its information about module and pretends it has never been loaded.
Use this when you remove a module from your system, or misspell a module's
name when referring to it, to prevent load-modules or compile-modules from
attempting to load or compile the defunct module.


mload module &key path (compile nil) (force t) (print nil)       [Function]
                  (verbose *mload-verbose*)

   Loads a module.  If compile is true, mload first calls mcomp with :force
nil to compile the module; then it loads module.
   If force is nil, then the module is only loaded if it has never been
loaded or has been changed since the last time it was loaded.  Path is used
by find-module-file (see below) to determine the pathname of the module.
Print and verbose are passed to load.


mcomp module &key path (force t) (load t) (print nil)            [Function]
                  (verbose *mload-verbose*)

   Compiles a module and, if load is t, loads the result.
   If force is nil, the module is only compiled if the lisp file has been
changed   Path is  sed by  ind module fi e to
module.. Print anduverbosefare-passed-tolload.determine the pathname of the
   Note that mcomp will refuse to compile a module that has :compile nil in
its provide-module statement.


load-modules &key (include nil) (exclude nil) (compile nil)      [Function]
                  (force nil) (print nil)
                  (verbose *load-verbose*) (query nil)

   Calls mload on the all the modules given in include except for those
given in exclude.  If include is nil, then a list of all existing modules
will be used as the include argument.  If query is t, then for each module
that needs loading, you will be prompted as to whether you want to load the
module.  Other arguments are passed through to mload.


compile-modules &key (include nil) (exclude nil) (load t)        [Function]
                     (force nil) (print nil)
                     (verbose *load-verbose*) (query nil)

   Calls mcomp on the all the modules given in include except for those
given in exclude.  If include is nil, then a list of all existing modules
will be used as the include argument.  If query is t, then for each module
that needs compiling, you will be prompted as to whether you want to
compile the module.  Other arguments are passed through to mcomp.


uncompiled-modules                                               [Function]

   Returns a list of all modules which are uncompiled in the current lisp
environment.  It can be used as the include argument to compile-modules on
machines where file access is slow.  It can also be used to obtain a list
of suspects for why your code might be running slower than usual.  Modules
in this list may not actually need compilation; it may just be that the
compiled versions aren't loaded.


modules-dependent-on &rest modules                               [Function]

   Returns a list of all modules which depend on any of modules, a list of
modules and/or module names.  Use this function to pass a list of modules
to compile to compile-modules when you want to (re)compile only those
modules that depend on, say, a single module you just changed, without
compiling all modules that might need it.


search-for-file file &optional                                   [Function]
			       (search-path *module-search-path*)

   Searches for file in each directory on search-path.  If file does not
specify a file type, then both lisp and binary files are tried, and the one
with the most recent write-date is returned.


find-module-file module &optional file lsp-only                  [Function]

   Finds the pathname of the file from which module should be loaded.  If
file does not contain a name, then the module name (converted to a file
name as appropriate for the current configuration) is used.  If lsp-only is
t, then only lisp source files will be returned, not compiled binary files.
Find-module-file uses search-for-file.
   The functions mload, mcomp, and require-module all call find-module-file
to translate module names into pathnames.
